package com.fcc.wfly.entitlement.controller;

import com.fcc.wfly.entitlement.hal.*;
import com.hp.it.gssops.beans.ObligationInfo;
import com.fcc.wfly.common.domain.ErrorHandleConst;
import com.fcc.wfly.entitlement.domain.CarePackObligationInfo;
import com.fcc.wfly.entitlement.domain.ObligationClientInfo;
import com.fcc.wfly.entitlement.service.impl.ObligationService;
import com.fcc.wfly.utils.AuthUtils;
import com.fcc.wfly.utils.ConfigUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.map.MultiValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

@RestController
public class ObligationController {


    private static final String HEADER_SERIAL_NUMBER = "serialNumber";
    private static final String HEADER_PRODUCTION_ID = "productID";
    private static final String HEADER_SHIP_TO_COUNTRY = "shipToCountry";
    private static final String HEADER_SHIP_TO_DATE = "shipToDate";
    private static final String HEADER_CONTENT_TOPIC = "Content-Topic";
    private static final String HEADER_CLIENT_ID = "Client-ID";
    private static final String HEADER_CONTENT_MD5 = "Content-MD5";
    private static final String HEADER_DEVICE_PRODUCT_NUMBER = "Device-Product-Number";
    private static final String HEADER_DEVICE_SERIAL_NUMBER = "Device-Serial-Number";
    private static final String HEADER_CONTENT_FILENAME = "Content-Filename";
    private static final String HEADER_DEVICE_MODEL_NAME = "Device-Model-Name";
    private static final String HEADER_DATE = "Date";
    private static final String HEADER_AUTHORIZATION = "X-API-KEY";
    private static final String HEADER_CONTENT_TYPE = "Content-Type";
    private static final String HEADER_CONTENT_LENGTH = "Content-Length";
    private static final String HEADER_USER_AGENT = "User-Agent";
    private static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For";
    private static final String HEADER_CACHE_CONTROL = "Cache-Control";

    private static final boolean MD5_CHECK_ENABLED = "true".equalsIgnoreCase(ConfigUtils.getProperty("md5.enabled"));
    private static final String KEY_TEMP_FOLDER = "TEMP_FOLDER";
    private static final String KEY_TARGET_FOLDER = "TARGET_FOLDER";
    private static final String KEY_QUARANTINE_FOLDER = "QUARANTINE_FOLDER";
    private static final boolean TRAFFIC_CONTROL_ENABLED = "true".equalsIgnoreCase(ConfigUtils.getProperty("traffic_control.enabled"));

    private static final String Mode_Active = "Active";
    private static final String Mode_Latest = "Latest";
    private static final String Mode_All = "All";


	protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ObligationService obligationService;
	private MultiValueMap res;


    @RequestMapping("/GetObligations")
    public HttpEntity<ObligationClientInfoJson> getObligations(HttpServletRequest request, HttpServletResponse response) {
        if (AuthUtils.auth(request)) {
            String serialNumber = request.getParameter("serialNumber");
            String productID = request.getParameter("productID");
            String mode = request.getParameter("Mode");
            
            // Error Handle - Params Validation
            try {
            	ErrorHandleConst.PnSnParamsValidate(productID,serialNumber);
            } catch (Exception e) {
				if (e.getMessage().startsWith(ErrorHandleConst.PN_NOT_EMPTY) ||
					e.getMessage().startsWith(ErrorHandleConst.SN_NOT_EMPTY) ||
					e.getMessage().startsWith(ErrorHandleConst.SN_OVER_LIMIT) ||
					e.getMessage().startsWith(ErrorHandleConst.PN_OVER_LIMIT)){
					res = new MultiValueMap();
					res.put("error", "No data found");
				}
				logger.info("【{}】Bad Request:{}", "GetObligations", e.getMessage());
				return new ResponseEntity(res, HttpStatus.BAD_REQUEST);
            }
            ObligationClientInfoJson obligationClientInfoJson = new ObligationClientInfoJson();
            try {
                ObligationClientInfo obligationInfo = obligationService.retrieveActiveOrLatestServiceObligationByProductIdentifier(serialNumber, productID, null, null);
                // set hal property
                BeanUtils.copyProperties(obligationClientInfoJson, obligationInfo);
               // obligationClientInfoJson.add(linkTo(methodOn(ObligationController.class).getObligations(request, response)).withSelfRel());
                if (obligationInfo != null) {
                    if (mode != null) {
                        //get all
                        if (mode.equalsIgnoreCase(Mode_All)) {
                            this.getAllMode(obligationInfo, obligationClientInfoJson);
                            //get active
                        } else if (mode.equalsIgnoreCase(Mode_Active)) {
                            this.getActiveMode(obligationInfo, obligationClientInfoJson);
                            //get latest
                        } else if (mode.equalsIgnoreCase(Mode_Latest)) {
                            this.getLatestMode(obligationInfo, obligationClientInfoJson);
                        }
                    } else {
                        //default is get all
                        this.getAllMode(obligationInfo, obligationClientInfoJson);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new ResponseEntity<ObligationClientInfoJson>(obligationClientInfoJson, HttpStatus.OK);
        } else {
            return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }

    }

    @RequestMapping("/IsPrinterEntitled")
    public HttpEntity<ObligationIndicatorInfoJson> isPrinterEntitled(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (AuthUtils.auth(request)) {
            String serialNumber = request.getParameter("serialNumber");
            String productID = request.getParameter("productID");
            
            // Error Handle - Params Validation
            try {
            	ErrorHandleConst.PnSnParamsValidate(productID,serialNumber);
            } catch (Exception e) {
				if (e.getMessage()==ErrorHandleConst.PN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "IsPrinterEntitled", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "IsPrinterEntitled", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "IsPrinterEntitled", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.PN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "IsPrinterEntitled", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				return new ResponseEntity(res, HttpStatus.BAD_REQUEST);
            }            
            ObligationInfo obligationInfo = obligationService.isPrinterEntitle(productID, serialNumber);
            ObligationIndicatorInfoJson obligationIndicatorInfoJson = new ObligationIndicatorInfoJson();
            if (obligationInfo != null) {
                //obligationIndicatorInfoJson.add(linkTo(methodOn(ObligationController.class).isPrinterEntitled(request, response)).withSelfRel());
                obligationIndicatorInfoJson.embedExistsIndicator(obligationInfo.getExistsIndicator());
                obligationIndicatorInfoJson.embedErrorMessage(obligationInfo.getErrorMessage());
            }
            return new ResponseEntity<ObligationIndicatorInfoJson>(obligationIndicatorInfoJson, HttpStatus.OK);
        } else {
            return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }
    }


    @RequestMapping("/IsPrinterUnderSupportContract")
    public HttpEntity<ObligationContractInfoJson> isPrinterUnderSupportContract(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (AuthUtils.auth(request)) {
            String serialNumber = request.getParameter("serialNumber");
            String productID = request.getParameter("productID");
            
            // Error Handle - Params Validation
            try {
            	ErrorHandleConst.PnSnParamsValidate(productID,serialNumber);
            } catch (Exception e) {
				if (e.getMessage()==ErrorHandleConst.PN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "IsPrinterUnderSupportContract", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "IsPrinterUnderSupportContract", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "IsPrinterUnderSupportContract", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.PN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "IsPrinterUnderSupportContract", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				return new ResponseEntity(res, HttpStatus.BAD_REQUEST);
            }                        
            ObligationClientInfo obligationInfo = obligationService.retrieveActiveOrLatestServiceObligationByProductIdentifier(serialNumber, productID, null, null);
            ObligationContractInfoJson obligationContractInfoJson = new ObligationContractInfoJson();
            List<String> overallDate = new ArrayList();
            // get active contract date
            if (obligationInfo != null) {
                if (obligationInfo.getCi() != null && obligationInfo.getCi().getActive().equalsIgnoreCase("TRUE") && obligationInfo.getCi().getOverallContractStartDate() != null) {
                    overallDate.add(obligationInfo.getCi().getOverallContractStartDate());
                    overallDate.add(obligationInfo.getCi().getOverallContractEndDate());
                }
                List<CarePackObligationInfo> carePackObligationInfoList = obligationInfo.getCarePackObligationInfo();
                if (!carePackObligationInfoList.isEmpty()) {
                    for (CarePackObligationInfo carePackObligationInfo : carePackObligationInfoList) {
                        if (carePackObligationInfo.getActive().equalsIgnoreCase("TRUE")) {
                            overallDate.add(carePackObligationInfo.getOverallCarepackStartDate());
                            overallDate.add(carePackObligationInfo.getOverallCarepackEndDate());
                        }
                    }
                }
                if (obligationInfo.getWi() != null && obligationInfo.getWi().getActive() != null && obligationInfo.getWi().getActive().equalsIgnoreCase("TRUE")) {
                    overallDate.add(obligationInfo.getWi().getOverallWarrantyStartDate());
                    overallDate.add(obligationInfo.getWi().getOverallWarrantyEndDate());
                }
            }
            if (!overallDate.isEmpty()) {
                int i = overallDate.size();
                Collections.sort(overallDate);
                obligationContractInfoJson.setActive("TRUE");
                obligationContractInfoJson.setOverallContractStartDate(overallDate.get(0));
                obligationContractInfoJson.setOverallContractEndDate(overallDate.get(i - 1));
            } else {
                obligationContractInfoJson.setActive("FALSE");
                obligationContractInfoJson.setOverallContractStartDate("");
                obligationContractInfoJson.setOverallContractEndDate("");
            }
           // obligationContractInfoJson.add(linkTo(methodOn(ObligationController.class).isPrinterUnderSupportContract(request, response)).withSelfRel());
            // get active warranty date
            return new ResponseEntity<ObligationContractInfoJson>(obligationContractInfoJson, HttpStatus.OK);
        } else {
            return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }

    }


    private void getActiveMode(ObligationClientInfo obligationInfo, ObligationClientInfoJson obligationClientInfoJson) throws InvocationTargetException, IllegalAccessException {
        if (obligationInfo.getCi() != null && obligationInfo.getCi().getActive() != null && obligationInfo.getCi().getActive().equalsIgnoreCase("TRUE")) {
            // get active contract
            ContractInfoJson contractInfoJson = new ContractInfoJson();
            BeanUtils.copyProperties(contractInfoJson, obligationInfo.getCi());
            obligationClientInfoJson.embedContract(contractInfoJson);
        }
        if (!obligationInfo.getCarePackObligationInfo().isEmpty()) {
            //get active CarePack
            List<CarePackObligationInfo> carePackObligationInfoList = obligationInfo.getCarePackObligationInfo();
            List<CarePackObligationInfoJson> carePackObligationInfoJsonList = new ArrayList<CarePackObligationInfoJson>();
            for (CarePackObligationInfo carePackObligationInfo : carePackObligationInfoList) {
                if (carePackObligationInfo.getActive().equalsIgnoreCase("TRUE")) {
                    CarePackObligationInfoJson carePackObligationInfoJson = new CarePackObligationInfoJson();
                    BeanUtils.copyProperties(carePackObligationInfoJson, carePackObligationInfo);
                    carePackObligationInfoJsonList.add(carePackObligationInfoJson);
                }
            }
            obligationClientInfoJson.embedCarepack(carePackObligationInfoJsonList);
        }
        if (obligationInfo.getWi() != null && obligationInfo.getWi().getActive() != null && obligationInfo.getWi().getActive().equalsIgnoreCase("TRUE")) {
            // get active Warranty
            WarrantyInfoJson warrantyInfoJson = new WarrantyInfoJson();
            BeanUtils.copyProperties(warrantyInfoJson, obligationInfo.getWi());
            obligationClientInfoJson.embedWarranty(warrantyInfoJson);
        }
    }

    private void getLatestMode(ObligationClientInfo obligationInfo, ObligationClientInfoJson obligationClientInfoJson) throws InvocationTargetException, IllegalAccessException, ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        long currentTime = new Date().getTime();
        if (obligationInfo.getCi() != null) {
            String overallEndDate = obligationInfo.getCi().getOverallContractEndDate();
            if (overallEndDate != null) {
                long endDate = sdf.parse(overallEndDate).getTime();
                if (currentTime >= endDate) {
                    // get latest contract
                    ContractInfoJson contractInfoJson = new ContractInfoJson();
                    BeanUtils.copyProperties(contractInfoJson, obligationInfo.getCi());
                    obligationClientInfoJson.embedContract(contractInfoJson);
                }
            }
        }
        if (!obligationInfo.getCarePackObligationInfo().isEmpty()) {
            //get latest CarePack
            List<CarePackObligationInfo> carePackObligationInfoList = obligationInfo.getCarePackObligationInfo();
            List<CarePackObligationInfoJson> carePackObligationInfoJsonList = new ArrayList<CarePackObligationInfoJson>();
            Collections.sort(carePackObligationInfoList, new Comparator<CarePackObligationInfo>() {
                public int compare(CarePackObligationInfo comp1, CarePackObligationInfo comp2) {
                    return comp2.getOverallCarepackEndDate().compareTo(comp1.getOverallCarepackEndDate());
                }
            });
            for (CarePackObligationInfo carePackObligationInfo : carePackObligationInfoList) {
                if (carePackObligationInfo.getActive().equalsIgnoreCase("TRUE")) {
                    CarePackObligationInfoJson carePackObligationInfoJson = new CarePackObligationInfoJson();
                    BeanUtils.copyProperties(carePackObligationInfoJson, carePackObligationInfo);
                    carePackObligationInfoJsonList.add(carePackObligationInfoJson);
                } else if (currentTime >= sdf.parse(carePackObligationInfo.getOverallCarepackEndDate()).getTime()) {
                    CarePackObligationInfoJson carePackObligationInfoJson = new CarePackObligationInfoJson();
                    BeanUtils.copyProperties(carePackObligationInfoJson, carePackObligationInfo);
                    carePackObligationInfoJsonList.add(carePackObligationInfoJson);
                }
            }
            Collections.sort(carePackObligationInfoJsonList, new Comparator<CarePackObligationInfoJson>() {
                public int compare(CarePackObligationInfoJson comp1, CarePackObligationInfoJson comp2) {
                    return comp2.getOverallCarepackEndDate().compareTo(comp1.getOverallCarepackEndDate());
                }
            });
            obligationClientInfoJson.embedCarepack(carePackObligationInfoJsonList.get(0));
        }
        if (obligationInfo.getWi() != null && obligationInfo.getWi().getOverallWarrantyEndDate() != null) {
            //get latest Warranty
            if (currentTime >= sdf.parse(obligationInfo.getWi().getOverallWarrantyEndDate()).getTime()) {
                WarrantyInfoJson warrantyInfoJson = new WarrantyInfoJson();
                BeanUtils.copyProperties(warrantyInfoJson, obligationInfo.getWi());
                obligationClientInfoJson.embedWarranty(warrantyInfoJson);
            }
        }
    }


    private void getAllMode(ObligationClientInfo obligationInfo, ObligationClientInfoJson obligationClientInfoJson) throws InvocationTargetException, IllegalAccessException {
        //  set ContractInfo property
        if (obligationInfo.getCi() != null) {
            ContractInfoJson contractInfoJson = new ContractInfoJson();
            BeanUtils.copyProperties(contractInfoJson, obligationInfo.getCi());
            obligationClientInfoJson.embedContract(contractInfoJson);
        }
        // set CarePackObligationInfo property
        if (obligationInfo.getCarePackObligationInfo() != null) {
            List<CarePackObligationInfo> carePackObligationInfoList = obligationInfo.getCarePackObligationInfo();
            List<CarePackObligationInfoJson> carePackObligationInfoJsonList = new ArrayList<CarePackObligationInfoJson>();
            for (CarePackObligationInfo carePackObligationInfo : carePackObligationInfoList) {
                CarePackObligationInfoJson carePackObligationInfoJson = new CarePackObligationInfoJson();
                BeanUtils.copyProperties(carePackObligationInfoJson, carePackObligationInfo);
                carePackObligationInfoJsonList.add(carePackObligationInfoJson);
            }
            obligationClientInfoJson.embedCarepack(carePackObligationInfoJsonList);
        }
        // set WarrantyInfo property
        if (obligationInfo.getWi() != null) {
            WarrantyInfoJson warrantyInfoJson = new WarrantyInfoJson();
            BeanUtils.copyProperties(warrantyInfoJson, obligationInfo.getWi());
            obligationClientInfoJson.embedWarranty(warrantyInfoJson);
        }
    }


}